package cn.saltybe.analysis.handler;

import cn.saltybe.analysis.util.ApiResponse;
import cn.saltybe.analysis.util.ApiResponseCode;
import cn.saltybe.analysis.util.ApiResponseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    private static final String logExceptionFormat = "Capture Exception By GlobalExceptionHandler: Code: %s Detail: %s";
    private static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    //运行时异常
    @ExceptionHandler(RuntimeException.class)
    public String runtimeExceptionHandler(RuntimeException ex) {
        return resultFormat(ApiResponseCode.RUNTIME_EXCEPTION, ex);
    }

    //空指针异常
    @ExceptionHandler(NullPointerException.class)
    public String nullPointerExceptionHandler(NullPointerException ex) {
        return resultFormat(ApiResponseCode.NULL_POINTER_EXCEPTION, ex);
    }

    //类型转换异常
    @ExceptionHandler(ClassCastException.class)
    public String classCastExceptionHandler(ClassCastException ex) {
        return resultFormat(ApiResponseCode.CLASS_CAST_EXCEPTION, ex);
    }

    //IO异常
    @ExceptionHandler(IOException.class)
    public String iOExceptionHandler(IOException ex) {
        return resultFormat(ApiResponseCode.IO_EXCEPTION, ex);
    }

    //未知方法异常
    @ExceptionHandler(NoSuchMethodException.class)
    public String noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        return resultFormat(ApiResponseCode.NO_SUCH_METHOD_EXCEPTION, ex);
    }

    //数组越界异常
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public String indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        return resultFormat(ApiResponseCode.INDEX_OUT_OF_BOUNDS_EXCEPTION, ex);
    }

    //400错误
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public String requestNotReadable(HttpMessageNotReadableException ex) {
        System.out.println("!!! 400: requestNotReadable");
        return resultFormat(ApiResponseCode.REQUEST_NOT_READABLE, ex);
    }

    //400错误
    @ExceptionHandler({TypeMismatchException.class})
    public String requestTypeMismatch(TypeMismatchException ex) {
        System.out.println("!!! 400: TypeMismatchException");
        return resultFormat(ApiResponseCode.TYPE_MISMATCH, ex);
    }

    //400错误
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public String requestMissingServletRequest(MissingServletRequestParameterException ex) {
        System.out.println("!!! 400: MissingServletRequest");
        return resultFormat(ApiResponseCode.MISSING_SERVLET_REQUEST, ex);
    }

    //405错误
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public String request405(HttpRequestMethodNotSupportedException ex) {
        return resultFormat(ApiResponseCode.HTTP_REQUEST_METHOD_NOT_SUPPORTED, ex);
    }

    //406错误
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public String request406(HttpMediaTypeNotAcceptableException ex) {
        System.out.println("!!! 406: Http media type not acceptable");
        return resultFormat(ApiResponseCode.HTTP_MEDIA_TYPE_NOT_ACCEPTABLE, ex);
    }

    //500错误
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public String server500(RuntimeException ex) {
        System.out.println("!!! 500: Server runtime exception");
        return resultFormat(ApiResponseCode.RUNTIME_EXCEPTION, ex);
    }

    //栈溢出
    @ExceptionHandler({StackOverflowError.class})
    public String requestStackOverflow(StackOverflowError ex) {
        return resultFormat(ApiResponseCode.STACK_OVERFLOW, ex);
    }

    //其他错误
    @ExceptionHandler({Exception.class})
    public String exception(Exception ex) {
        return resultFormat(ApiResponseCode.UNKNOWN_EXCEPTION, ex);
    }

    private <T extends Throwable> String resultFormat(ApiResponseCode code, T ex) {
        ex.printStackTrace();
        log.error(String.format(logExceptionFormat, code, ex.getMessage()));
        return ApiResponse.buildFailResponse(ApiResponseStatus.ERROR, code, ex.getMessage()).toString();
    }
}
